﻿using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using PT.Common;

namespace PT.Patterns.Tests {
    /// <summary>
    /// Unit tests Pattern class
    /// </summary>
    [TestClass]
    public class PatternTest {
       
        [TestMethod]
        public void PatternPartsTest() {
            Rational d4Th = Rational.Quarter, d8Th = Rational.Eight, d16Th = Rational.Sixteenth;

            var p1 = new Pattern {
                new Note {Duration = d16Th}, new Note {Duration = d8Th}, 
                new Note {Duration = d16Th}, new Note {Duration = d8Th}, 
                new Note {Duration = d8Th}};
            Assert.AreEqual(new Rational(2, 4), p1.Duration);
            Assert.AreEqual(2, p1.PatternParts(d4Th));

            var p2 = new Pattern {new Note {Duration = new Rational(2, 12)}, new Note {Duration = new Rational(3, 12)}};
            Assert.AreEqual(new Rational(5,12), p2.Duration);
            Assert.AreEqual(5, p2.PatternParts(d4Th));

            var p3 = new Pattern {new Note{Duration = d8Th}, new Note {Duration = d16Th}, new Note{Duration = d8Th}};
            Assert.AreEqual(new Rational(5,16), p3.Duration);
            Assert.AreEqual(5, p3.PatternParts(d4Th));

            var p4 = Rudiments.SingleStrokeFour;
            Assert.AreEqual(new Rational(1,4), p4.Duration);
            Assert.AreEqual(1, p4.PatternParts(d4Th));
        }

        [TestMethod]
        public void SplitTest() {
            var p1 = Rudiments.SingleParadiddle; // 2*4/16 = 1/2

            var split1 = p1.Split(Rational.Quarter);
            CheckSplit(p1, split1, 2);

            var split2 = p1.Split(Rational.Eight);
            CheckSplit(p1, split2, 4);

            var split3 = p1.Split(new Rational(3, 5));
            CheckSplit(p1, split3, 5);
        }

        static void CheckSplit(Pattern pattern, ICollection<Pattern> parts, int expectedPartCount) {
            Assert.AreEqual(expectedPartCount, parts.Count);

            var i = 0;
            var partDurationSum = new Rational(0, 1);
            var noteCount = 0;
            foreach(var part in parts) {
                foreach (Note t in part) {
                    Assert.AreEqual(pattern[i], t);
                    partDurationSum += t.Duration;
                    i = (i + 1) % pattern.Count;
                    ++noteCount;
                }
            }

            Assert.IsTrue(noteCount % pattern.Count == 0);
            Assert.AreEqual(1, (partDurationSum / pattern.Duration).Denominator);
        }
    }
}
